package prv.pursuivant.unimportant.scraps;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import prv.pursuivant.config.CategorySerializer;
import prv.pursuivant.config.impl.XStreamCategorySerializer;
import prv.pursuivant.config.impl.XStreamCategorySerializerModule;
import prv.pursuivant.core.AchievType;
import prv.pursuivant.core.AchievTypesTree;
import prv.pursuivant.core.AchievTypesTreeImpl;
import prv.pursuivant.core.impl.CategoryAchievType;
import prv.pursuivant.core.impl.KindImpl;
import prv.pursuivant.core.impl.MetaAchievType;
import prv.pursuivant.core.impl.NormalAchievType;
import prv.pursuivant.core.impl.NpcAchievType;
import prv.pursuivant.core.impl.SubcategoryAchievType;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.internal.Lists;
import com.google.inject.internal.Maps;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

class Node {
	KindImpl type;
	String id;
	String name;
	ArrayList<Node> criteria;

	static Node createNode(AchievTypesTree tree) {
		Map<String, Node> created = Maps.newHashMap();
		return createNode(tree, tree.getRoot(), created);
	}

	private static Node createNode(AchievTypesTree tree, AchievType achiev,
			Map<String, Node> created) {
		if (created.containsKey(achiev.getId()))
			return created.get(achiev.getId());
		Node node = new Node();
		node.type = (KindImpl) achiev.getKind();
		node.id = achiev.getId();
		node.name = achiev.getName();
		node.criteria = Lists.newArrayList();
		created.put(achiev.getId(), node);
		for (String crit : achiev.getCriteria())
			node.criteria.add(createNode(tree, tree.findAchievTypeById(crit),
					created));
		if (node.criteria.isEmpty())
			node.criteria = null;
		return node;
	}
}

public class TreeReformatter {

	/**
	 * @return
	 */
	private CategorySerializer makeRegularSerializer() {
		Injector injector = Guice
				.createInjector(new XStreamCategorySerializerModule());
		XStreamCategorySerializer serializer = injector
				.getInstance(XStreamCategorySerializer.class);
		return serializer;
	}

	/**
	 * @return
	 */
	private XStream makeUglyXStream() {
		XStream xstream = new XStream(new DomDriver());
		xstream.setMode(XStream.NO_REFERENCES);
		xstream.useAttributeFor(String.class);
		xstream.useAttributeFor(KindImpl.class);
		xstream.alias("achiev", Node.class);
		xstream.addImplicitCollection(Node.class, "criteria", "achiev",
				Node.class);
		return xstream;
	}

	/**
	 * @param args
	 * @throws IOException
	 */
	public static void main(String[] args) throws IOException {
		// new TreeReformatter().normalToNormal();
		// new TreeReformatter().normalToUgly();
		new TreeReformatter().uglyToNormal();
	}

	private void uglyToNormal() throws IOException {
		XStream xstream = makeUglyXStream();
		File fileUgly = new File("testWD/oldData/tree.xml");
		FileInputStream uglyStream = new FileInputStream(fileUgly);
		Node ugly = (Node) xstream.fromXML(uglyStream);
		uglyStream.close();

		AchievTypesTree tree = generateTree(ugly);

		CategorySerializer serializer = makeRegularSerializer();
		File normalFile = new File("testWD/config/category.fromUgly.168.xml");
		FileOutputStream normalStream = new FileOutputStream(normalFile);
		serializer.writeTree(tree, normalStream);
		normalStream.close();
	}

	private AchievTypesTree generateTree(Node node) {
		List<AchievType> allTheAchievements = Lists.newArrayList();
		Map<String, AchievType> done = Maps.newHashMap();
		AchievType achiev = generateAchiev(allTheAchievements, done, node, null);
		AchievTypesTree tree = new AchievTypesTreeImpl(allTheAchievements,
				achiev);
		return tree;
	}

	private AchievType generateAchiev(List<AchievType> allTheAchievements,
			Map<String, AchievType> done, Node node, String parentId) {
		if (done.containsKey(node.id))
			return done.get(node.id);
		AchievType result;
		List<String> criteria = Lists.newArrayList();
		if (null != node.criteria)
			for (Node crit : node.criteria) {
				criteria.add(crit.id);
			}
		switch (node.type) {
		case CATEGORY:
			result = new CategoryAchievType(node.name, node.id, criteria);
			break;
		case SUBCATEGORY:
			result = new SubcategoryAchievType(node.name, parentId, criteria);
			break;
		case NORMAL:
			result = new NormalAchievType(node.name, node.id, criteria);
			break;
		case META:
			result = new MetaAchievType(node.name, node.id, criteria);
			break;
		case NPC:
			result = new NpcAchievType(node.name, parentId);
			break;
		default:
			throw new IllegalArgumentException(node.type.toString());
		}

		done.put(result.getId(), result);

		if (null != node.criteria)
			for (Node crit : node.criteria) {
				@SuppressWarnings("unused")
				AchievType generatedAchiev = generateAchiev(allTheAchievements,
						done, crit, node.id);
				// allTheAchievements.add(generatedAchiev);
			}
		if (result.getKind() != KindImpl.CATEGORY)
			allTheAchievements.add(result);
		return result;
	}

	private void normalToUgly() throws IOException {
		CategorySerializer serializer = makeRegularSerializer();
		File file = new File("testWD/config/category.168.xml");
		FileInputStream fis = new FileInputStream(file);
		AchievTypesTree tree = serializer.readTree(fis);
		fis.close();
		Node ugly = Node.createNode(tree);
		XStream xstream = makeUglyXStream();
		File fileUgly = new File("testWD/oldData/tree.xml");
		FileOutputStream fos = new FileOutputStream(fileUgly);
		xstream.toXML(ugly, fos);
		fos.close();
	}

	private void normalToNormal() throws IOException {
		CategorySerializer serializer = makeRegularSerializer();
		File file = new File("runWD/config/category.168.xml");
		FileInputStream fis = new FileInputStream(file);
		AchievTypesTree tree = serializer.readTree(fis);
		fis.close();
		File fileUgly = new File("testWD/config/category.168.xml");
		FileOutputStream fos = new FileOutputStream(fileUgly);
		serializer.writeTree(tree, fos);
		fos.close();
	}

}
